#include <fst/fstlib.h>
#include <fst/script/arcsort.h>
#include <fst/compat.h>
#include <stdio.h>
#include <string.h>
#include "post_procs.h"

#define N_INDEX 5

using fst::SymbolTable;
using fst::StdArc;
using fst::StdVectorFst;


float w[N_INDEX] = {1, 1.5, 1.7, 1.7, 1.7};
int count = 0;
char ** wordList;
StdVectorFst strFst;
StdVectorFst wordFst[200];

void createWordFst(int ** charIndex, int nChar, double **prop) {
    StdVectorFst::StateId q, r;
    StdVectorFst wfst;
    int i, j;

    char *word = (char*) calloc(nChar+1, sizeof(char));
    word[nChar] = '\0';

    /// start state
    q = wfst.AddState();
    wfst.SetStart(q);

    /// get char
    for(i = 0; i < nChar; i++) {
        word[i] = charIndex[i][0] + 'a';
        r = wfst.AddState();
		for(j = 0; j < N_INDEX; j ++){
			/// add arc: iLabel, oLabel, weight, destState
			int lbl = charIndex[i][j] + 1;
			wfst.AddArc(q, StdArc(lbl, lbl, 2 - prop[i][j], r));
		}
		q = r;
	}
	wfst.SetFinal(q, 0); /// ID, weight

	///final state
	count++;
	char fstName[100];
    sprintf(fstName, "data/%d.fst", count);
	wfst.Write(fstName);
    wordFst[count-1] = wfst;

    /// add to string fst
    if(count == 1) {
        strFst = wfst;
    } else {
        Union(&strFst, wfst);
    }
//	/// create word fst for levenstein correction
//	StdVectorFst wfstlev;
//	/// start state
//	q = wfstlev.AddState();
//	wfstlev.SetStart(q);
//
//    for(i = 0; i < nChar; i ++){
//        r = wfstlev.AddState();
//        /// add arc: iLabel, oLabel, weight, destState
//        int lbl = (int) (word[i] - 'a' +1);
//        wfstlev.AddArc(q, StdArc(lbl, lbl, 0, r));
//        q = r;
//    }
//    wfstlev.SetFinal(q, 1); /// ID, weight
//
//	///final state
//	sprintf(fstName, "leven/%d.fst", count);
//	wfstlev.Write(fstName);


	wordList = (char **)realloc(wordList, count * sizeof(char*));
	wordList[count-1] = word;
}


int printStateFst(StdVectorFst fst_, StdVectorFst::StateId s, StdVectorFst::StateId* next) {
    fst::ArcIterator<StdVectorFst> aiter(fst_, s);
    fst::StdArc arc = aiter.Value();
    *next = arc.nextstate;
    return arc.ilabel;
}

char* printWordFst(StdVectorFst fst_) {
    char * out= (char*)calloc(30, sizeof(char));
    int i, val = 0;

    StdVectorFst::StateId start, cur, next;
    start = fst_.Start();
    if (start == fst::kNoStateId)
      return NULL;
    // initial state first

    out[0] = printStateFst(fst_, start, &next) - 1 + 'a';

    for(i = 1; i < fst_.NumStates() - 1; i++)
    {
        cur = next;
        if(( val = printStateFst(fst_, cur, &next)) != -1){
            out[i] = val - 1+'a';
        }
    }

    out[i+1] = '\0';
    return out;
}

void createOutputFst() {
    strFst.Write("str.fst");
    system("./sortFst.sh");
    int i;
    StdVectorFst *comStrFst = StdVectorFst::Read("com_str.fst");
    StdVectorFst outFst, shortestFst;
    for(i = 0; i < count; i++) {
        Compose(wordFst[i], *comStrFst, &outFst);
        ShortestPath(outFst, &shortestFst);
        char *s = printWordFst(shortestFst);
        if(s != NULL)
            printf("%s ", s);
        else {
            printf("%s ", wordList[i]);
        }
    }
    printf("\n\n");
    count = 0;
}

void readOutputFst() {
    int i;
    StdVectorFst* wfst;
    char fstName[100];
    for(i = 0; i < count; i++) {
//        printf("%d ", i);
        sprintf(fstName, "out/%d.fst", i+1);
        wfst = StdVectorFst::Read(fstName);
        char *s = printWordFst(*wfst);

        if(s != NULL)
            printf("%s ", s);
        else {
            printf("%s ", wordList[i]);
        }
    }
    count = 0;
}
